﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Net.Sockets;
using Configuration;
using System.Net;
using System.Net.NetworkInformation;

namespace Core
{
    public class Core
    {
        public static int threadsCounter = 0;

        private static Thread mainThread;
        private static TcpListener tcpListener;

        ThreadSafeList<WorkerThread> lstWorkerThreads = new ThreadSafeList<WorkerThread>();

        public bool Listen()
        {
            try
            {
                bool listen = _Listen();
                if (!listen)
                {
                    Console.WriteLine("Error while listening, is the port " + Configuration.Configuration.port + " in use?");
                    return false;
                }

                Console.WriteLine(string.Format("Listeing at {0}:{1}", "*", Configuration.Configuration.port));

                List<IPlugin.IPlugin> plugins = Plugins.PluginManager.LoadPlugins();
                if (plugins.Count > 0)
                {
                    Console.WriteLine("\r\nPlugins loaded:\r\n---------------");
                    foreach (IPlugin.IPlugin plugin in plugins)
                        Console.WriteLine(string.Concat("\t+ ", plugin.Name));
                }
            }
            catch
            {
                return false;
            }

            return true;
        }

        private bool _Listen()
        {
            int port = Configuration.Configuration.port;


            IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
            TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();

            tcpListener = new TcpListener(port);
            try
            {
                tcpListener.Start();
            }
            catch
            {
                return false;
            }
            ThreadSafeQueue<System.Threading.Thread> queueThreads = new ThreadSafeQueue<Thread>();
            
            mainThread = new Thread(() =>
            {
                Console.Title = string.Format("{0}/{1}", threadsCounter, Configuration.Configuration.maxThreads);

                while (true)
                {
                    // Cleans the worker lists, removing workersthreads from it when a thread has been aborted
                    CleanWorkersList();
                    if ((threadsCounter >= Configuration.Configuration.maxThreads) ||!tcpListener.Pending())
                    {
                        System.Threading.Thread.Sleep(50);
                        continue;
                    }

                    TcpClient client = tcpListener.AcceptTcpClient();

                    Worker worker = new Worker(client);
                    Interlocked.Increment(ref threadsCounter);
                    Console.Title = string.Format("{0}/{1}", threadsCounter, Configuration.Configuration.maxThreads);
                    Thread t = new Thread(worker.Process);
                    t.IsBackground = true;
                    WorkerThread wThread = new WorkerThread(worker, t);
                    wThread.Finished += wThread_Finished;
                    lstWorkerThreads.Add(wThread);

                    ThreadPool.QueueUserWorkItem((_) =>
                        {
                            wThread.Start();
                        });
                    //wThread.thread.Join();
                    //threadsCounter--;

                    //ThreadPool.QueueUserWorkItem((_) =>
                    //{
                    //    Worker worker = new Worker(client);
                    //    try
                    //    {
                    //        Interlocked.Increment(ref threadsCounter);
                    //        Thread t = new Thread(worker.Process);
                    //        t.IsBackground = true;
                    //        WorkerThread wThread = new WorkerThread(worker, t);
                    //        lstWorkerThreads.Add(wThread);
                    //        wThread.Start();
                    //        wThread.thread.Join();
                    //    }
                    //    catch (Exception ex)
                    //    {
                    //        Log.Log.LogThisConsole(string.Format("unknow error: {0}", ex.Message));
                    //    }
                    //    finally
                    //    {
                    //        Interlocked.Decrement(ref threadsCounter);
                    //    }
                    //}, null);
                }
            });

            mainThread.IsBackground = true;
            mainThread.Start();
            return true;
        }

        void wThread_Finished(object sender, EventArgs e)
        {
            Interlocked.Decrement(ref threadsCounter);
            Console.Title = string.Format("{0}/{1}", threadsCounter, Configuration.Configuration.maxThreads);

            //throw new NotImplementedException();
        }

        private void CleanWorkersList()
        {
            for (int i = lstWorkerThreads.Count - 1; i >= 0; i--)
            {
                WorkerThread wt = (WorkerThread)lstWorkerThreads[i];

                // Check if the thread is already aborted, if so the workerthread is removed from the list
                if (!wt.IsActive())
                {
                    lstWorkerThreads.RemoveAt(i);
                    continue;
                }

                // Check iddle time for readding from the socket. If exceeded thread is aborted
                //if (wt.worker.executionRead.ElapsedMilliseconds > Configuration.Configuration.maxIddleReceiving)
                //    lstWorkerThreads[i].thread.Abort();
                // Check iddle time for sending data through the socket. If exceeded thread is aborted
                //if (wt.worker.executionRead.ElapsedMilliseconds > Configuration.Configuration.maxIddleSending)
                //    lstWorkerThreads[i].thread.Abort();
            }
        }

        public static void Stop()
        {
            if (tcpListener != null)
                tcpListener.Stop();
            if (mainThread != null)
                mainThread.Abort();
        }
    }
}
